package com.dingreading.cloud.soms.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.util.*;
import com.dingreading.cloud.common.util.excel.ExcelHandler;
import com.dingreading.cloud.common.util.excel.MergeFieldBean;
import com.dingreading.cloud.soms.dto.CmOrderCountDto;
import com.dingreading.cloud.soms.dto.CmServiceCountDto;
import com.dingreading.cloud.soms.dto.CountDto;
import com.dingreading.cloud.soms.dto.MemberUidSourceDto;
import com.dingreading.cloud.soms.entity.Cmorders;
import com.dingreading.cloud.soms.entity.table.CmordersTableDef;
import com.dingreading.cloud.soms.mapper.CmordersMapper;
import com.dingreading.cloud.soms.service.CmOrderCountService;
import com.dingreading.cloud.soms.service.CmordersService;
import com.dingreading.cloud.soms.service.CmservicesService;
import com.dingreading.cloud.soms.service.MembersService;
import com.dingreading.cloud.soms.util.EnumCustomSource;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务层实现。
 *
 * @author Administrator
 * @since 2023-11-22
 */
@Service
public class CmOrderCountServiceImpl extends BaseServiceImpl<CmordersMapper, Cmorders, CmordersTableDef> implements CmOrderCountService {

    @Resource
    private MembersService membersService;
    @Resource
    private CmordersService cmordersService;
    @Resource
    private CmservicesService cmservicesService;


    @Override
    protected CmordersTableDef getTable() {
        return CmordersTableDef.cmorders;
    }

    // 会员来源分类
    private List<String> customSourceList = Lists.newArrayList("线上", "自然到访", "转介绍", "地推", "其他");


    @Override
    public R<Object> cmOrderCount(
            String corpUid, String storeUid, String staffUid, String beginDate, String endDate
    ) throws Exception {
        R<Object> r = judgeDate(beginDate, endDate);
        if (R.isError(r))
            return r;

        // 获取统计数据
        List<CountDto> countList = getCountList(storeUid, beginDate, endDate);

        LinkedHashMap<String, List<CountDto>> map = countList.stream().collect(Collectors.groupingBy(CountDto::getTitle, LinkedHashMap::new, Collectors.toList()));
        JSONArray array = new JSONArray();
        for (Map.Entry<String, List<CountDto>> entry : map.entrySet()) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("name", entry.getKey());
            jsonObject.put("data", entry.getValue());
            array.add(jsonObject);
        }

        return R.ok(array);
    }


    @Override
    public void export(
            HttpServletResponse response, String corpUid, String storeUid, String staffUid, String beginDate, String endDate
    ) throws Exception {
        R<Object> r = judgeDate(beginDate, endDate);
        if (R.isError(r))
            throw new DescribeException(r.getMsg());

        // 获取统计数据
        List<CountDto> countList = getCountList(storeUid, beginDate, endDate);

        // 文件名
        String fileName = "订单数据摘取分析" + beginDate + "至" + endDate;
        // 表单名
        String sheetName = "订单数据摘取分析";
        // 需合并的列
        List<MergeFieldBean> fieldMergeList = new ArrayList<>();
        fieldMergeList.add(new MergeFieldBean("title", 0));
        // 导出
        ExcelHandler.exportMergeExcel(response, countList, CountDto.class, fileName, sheetName, fieldMergeList);
    }


    /**
     * 获取统计数据
     */
    private List<CountDto> getCountList(String storeUid, String beginDate, String endDate) {
        List<CountDto> countList = new ArrayList<>();

        // 总线索会员
        int clueMemberCount = 0;
        String clueTitle = "总线索会员";
        List<MemberUidSourceDto> membersList = membersService.listByAddTimeBetween(storeUid, beginDate, endDate);
        if (CollectionUtils.isNotEmpty(membersList)) {
            Map<String, List<String>> memberMap = membersList.stream()
                    .collect(Collectors.groupingBy(members -> getCustomSource(members.getCustomSource()), Collectors.mapping(MemberUidSourceDto::getUid, Collectors.toList())));
            for (String type : customSourceList) {
                List<String> memberUidList = memberMap.get(type);
                int i = 0;
                if (CollectionUtils.isNotEmpty(memberUidList)) {
                    i = memberUidList.size();
                }
                countList.add(new CountDto(clueTitle, type, i + ""));
            }
            clueMemberCount = membersList.size();
        } else {
            for (String type : customSourceList) {
                countList.add(new CountDto(clueTitle, type, "0"));
            }
        }
        countList.add(new CountDto(clueTitle, "总数", clueMemberCount + ""));

        // 有效线索会员
        int clueEnableMemberCount = 0;
        String clueEnabledTitle = "有效线索会员";
        if (CollectionUtils.isNotEmpty(membersList)) {
            List<MemberUidSourceDto> clueEnabledMemberList = membersList.stream().filter(dto -> dto.getValidStatus().equals(1)).collect(Collectors.toList());
            Map<String, List<String>> memberMap = clueEnabledMemberList.stream()
                    .collect(Collectors.groupingBy(members -> getCustomSource(members.getCustomSource()), Collectors.mapping(MemberUidSourceDto::getUid, Collectors.toList())));
            for (String type : customSourceList) {
                List<String> memberUidList = memberMap.get(type);
                int count = 0;
                if (CollectionUtils.isNotEmpty(memberUidList)) {
                    count = memberUidList.size();
                }
                countList.add(new CountDto(clueEnabledTitle, type, count + ""));
            }
            clueEnableMemberCount = clueEnabledMemberList.size();
        } else {
            for (String type : customSourceList) {
                countList.add(new CountDto(clueEnabledTitle, type, "0"));
            }
        }
        countList.add(new CountDto(clueEnabledTitle, "总数", clueEnableMemberCount + ""));

        // 查询日期内的所有会员订单
        List<CmOrderCountDto> cmordersList = cmordersService.listByOrderDateBetween(storeUid, beginDate, endDate);
        List<CmOrderCountDto> newCmOrderList = new ArrayList<>();
        List<CmServiceCountDto> cmserviceList = new ArrayList<>();
        List<CmServiceCountDto> shouldRenewCmserviceList = new ArrayList<>();
        // 实际续费订单金额
        double renewAmount = 0;
        if (CollectionUtils.isNotEmpty(cmordersList)) {
            List<String> orderCodeList = new ArrayList<>();
            for (CmOrderCountDto dto : cmordersList) {
                if (dto.getOrderType().equals(EnumType.OrderType.NEW.getType()))
                    newCmOrderList.add(dto);
                if (dto.getOrderType().equals(EnumType.OrderType.RENEW.getType())) {
                    renewAmount = DoubleUtil.sum(renewAmount, dto.getOrderAmount());
                }
                orderCodeList.add(dto.getOrderCode());
            }
            cmserviceList = cmservicesService.cmserviceCountList(storeUid, orderCodeList);
            shouldRenewCmserviceList = cmservicesService.shouldRenewList(storeUid, beginDate, endDate);
        }

        // 开卡体验订单会员
        int openExpMemberCount = 0;
        String openExpTitle = "开卡体验订单会员";
        Map<String, Integer> openExpMemberMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(cmserviceList)) {
            Map<String, Map<String, List<CmServiceCountDto>>> openExpMap = cmserviceList.stream()
                    .filter(service -> service.getOrderType().equals(EnumType.OrderType.EXP.getType()) && service.getStatus().equals(EnumType.ServiceStatus.OPEN_CARD.getStatus()))
                    .collect(Collectors.groupingBy(dto -> getCustomSource(dto.getCustomSource()), Collectors.groupingBy(CmServiceCountDto::getMemberUid, Collectors.toList())));
            for (String type : customSourceList) {
                int count = 0;
                Map<String, List<CmServiceCountDto>> map = openExpMap.get(type);
                if (map != null && !map.isEmpty()) {
                    count += map.size();
                }
                openExpMemberCount += count;
                openExpMemberMap.put(type, count);
                countList.add(new CountDto(openExpTitle, type, count + ""));
            }
        } else {
            for (String type : customSourceList) {
                openExpMemberMap.put(type, 0);
                countList.add(new CountDto(openExpTitle, type, "0"));
            }
        }
        countList.add(new CountDto(openExpTitle, "总数", openExpMemberCount + ""));

        // 转正价签约
        int transferNewCount = 0;
        String transferNewTitle = "转正价签约";
        Map<String, Integer> transferNewMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(newCmOrderList)) {
            Map<String, Map<String, Long>> transferNewMemberMap = newCmOrderList.stream()
                    .collect(Collectors.groupingBy(dto -> getCustomSource(dto.getCustomSource()), Collectors.groupingBy(CmOrderCountDto::getMemberUid, Collectors.counting())));
            for (String type : customSourceList) {
                int count = 0;
                Map<String, Long> map = transferNewMemberMap.get(type);
                if (map != null && !map.isEmpty()) {
                    count += map.size();
                }
                transferNewCount += count;
                transferNewMap.put(type, count);
                countList.add(new CountDto(transferNewTitle, type, count + ""));
            }
        } else {
            for (String type : customSourceList) {
                transferNewMap.put(type, 0);
                countList.add(new CountDto(transferNewTitle, type, "0"));
            }
        }
        countList.add(new CountDto(transferNewTitle, "总数", transferNewCount + ""));

        // 体验转化率
        double expConversionRate = 0;
        String expConversionTitle = "体验转化率";
        if (transferNewCount != 0 && openExpMemberCount != 0)
            expConversionRate = DoubleUtil.mul(DoubleUtil.div(transferNewCount, openExpMemberCount, 2), 100);
        for (String type : customSourceList) {
            Integer a = openExpMemberMap.get(type);
            Integer b = transferNewMap.get(type);
            double rate = 0;
            if (a != 0 && b != 0) {
                rate = DoubleUtil.mul(DoubleUtil.div(b, a, 2), 100);
            }
            countList.add(new CountDto(expConversionTitle, type, rate + "%"));
        }
        countList.add(new CountDto(expConversionTitle, "总数", expConversionRate + "%"));

        // 新签金额(包含拓科)
        double newAmount = 0d;
        String newTitle = "新签金额";
        Map<String, Double> newCmorderAmountMap = cmordersList.stream()
                .filter(cmorders -> cmorders.getOrderType().equals(EnumType.OrderType.NEW.getType()) || cmorders.getOrderType().equals(EnumType.OrderType.EXT.getType()))
                .collect(Collectors.groupingBy(dto -> getCustomSource(dto.getCustomSource()),
                        Collectors.reducing(0.0, CmOrderCountDto::getOrderAmount, DoubleUtil::sum))
                );
        for (String type : customSourceList) {
            double amount = NepUtil.nullToZero(newCmorderAmountMap.get(type));
            if (amount > 0)
                newAmount = DoubleUtil.sum(newAmount, amount);
            countList.add(new CountDto(newTitle, type, amount + ""));
        }
        countList.add(new CountDto(newTitle, "总金额", newAmount + ""));

        // 续费
        int renewCount = 0;
        String renewTitle = "续费";
        // 应续费人数（4次课内除6年级）
        int shouldRenewCount = 0;
        if (CollectionUtils.isNotEmpty(shouldRenewCmserviceList)) {
            Map<String, Map<String, Long>> shouldRenewCmserviceMap = shouldRenewCmserviceList.stream()
                    .collect(Collectors.groupingBy(CmServiceCountDto::getMemberUid,
                            Collectors.groupingBy(cmservices -> getSubjectType(cmservices.getProductName()), Collectors.counting()))
                    );
            for (Map.Entry<String, Map<String, Long>> entry : shouldRenewCmserviceMap.entrySet()) {
                Map<String, Long> value = entry.getValue();
                shouldRenewCount += value.size();
            }
            // 实际续费人数
            Map<String, Map<String, Long>> renewCmserviceMap = cmserviceList.stream()
                    .filter(dto -> dto.getOrderType().equals(EnumType.OrderType.RENEW.getType()))
                    .collect(Collectors.groupingBy(CmServiceCountDto::getMemberUid,
                            Collectors.groupingBy(cmservices -> getSubjectType(cmservices.getProductName()), Collectors.counting()))
                    );
            for (Map.Entry<String, Map<String, Long>> entry : renewCmserviceMap.entrySet()) {
                Map<String, Long> value = entry.getValue();
                renewCount += value.size();
            }
        }
        // 提前续费人数
        int aheadRenewCount = 0;
        if (CollectionUtils.isNotEmpty(cmserviceList)) {
            Map<String, Map<String, List<CmServiceCountDto>>> aheadRenewCmserviceMap = cmserviceList.stream()
                    .filter(dto -> dto.getOrderType().equals(EnumType.OrderType.RENEW.getType())
                            && dto.getEnding().equals(0) && dto.getLessonStatus().equals(1) && dto.getLeftLessons() != null
                            && dto.getLeftLessons() >= 5
                    )
                    .collect(Collectors.groupingBy(CmServiceCountDto::getMemberUid,
                            Collectors.groupingBy(cmservices -> getSubjectType(cmservices.getProductName())))
                    );
            if (!aheadRenewCmserviceMap.isEmpty()) {
                for (Map.Entry<String, Map<String, List<CmServiceCountDto>>> entry : aheadRenewCmserviceMap.entrySet()) {
                    Map<String, List<CmServiceCountDto>> value = entry.getValue();
                    aheadRenewCount += value.size();
                }
            }
        }
        // 续费率
        int aRenewCount = shouldRenewCount + aheadRenewCount;
        int bRenewCount = renewCount + aheadRenewCount;
        double renewRate = 0;
        if (aRenewCount != 0 && bRenewCount != 0) {
            renewRate = DoubleUtil.mul(DoubleUtil.divCeil(bRenewCount, aRenewCount, 2), 100);
        }
        // 续费金额
        countList.add(new CountDto(renewTitle, "应续人数（4次课内除6年级）", shouldRenewCount + ""));
        countList.add(new CountDto(renewTitle, "实际续费人数", renewCount + ""));
        countList.add(new CountDto(renewTitle, "提前续费人数（5次课以上）", aheadRenewCount + ""));
        countList.add(new CountDto(renewTitle, "续费率", renewRate + "%"));
        countList.add(new CountDto(renewTitle, "续费金额", renewAmount + ""));

        // 量化数据呈现
        // 门店正价结课会员（含退费会员）
        int endingCount = 0;
        String quantizedDataTitle = "量化数据呈现";
        List<CmServiceCountDto> endingCmserviceList = cmservicesService.endingList(storeUid, beginDate, endDate);
        if (CollectionUtils.isNotEmpty(endingCmserviceList)) {
            Map<String, List<CmServiceCountDto>> list = endingCmserviceList.stream().collect(Collectors.groupingBy(CmServiceCountDto::getMemberUid));
            endingCount = list.size();
        }
        // 新签会员数
        int newMemberCount = 0;
        if (CollectionUtils.isNotEmpty(newCmOrderList)) {
            Map<String, List<CmOrderCountDto>> newCmorderMap = newCmOrderList.stream().collect(Collectors.groupingBy(CmOrderCountDto::getMemberUid));
            newMemberCount = newCmorderMap.size();
        }
        // 未结课会员数（含新签&续费）
        int noEndingCount = 0;
        if (CollectionUtils.isNotEmpty(cmserviceList)) {
            Map<String, List<CmServiceCountDto>> noEndingMap = cmserviceList.stream()
                    .filter(dto -> (!dto.getOrderType().equals(EnumType.OrderType.EXP.getType())
                            && !dto.getOrderType().equals(EnumType.OrderType.GIFT.getType()) && !dto.getOrderType().equals(EnumType.OrderType.REFUND.getType()))
                            && dto.getEnding().equals(0) && dto.getLessonStatus().equals(1) && dto.getLeftLessons() != null && dto.getLeftLessons() > 0)
                    .collect(Collectors.groupingBy(CmServiceCountDto::getMemberUid));
            if (!noEndingMap.isEmpty()) {
                noEndingCount = noEndingMap.size();
            }
        }
        // 净会员增长
        int newGrowthCount = newMemberCount - endingCount;
        // 现金流（新签+续费金额）
        double cashFlowAmount = DoubleUtil.sum(newAmount, renewAmount);
        countList.add(new CountDto(quantizedDataTitle, "门店正价结课会员（含退费会员）", endingCount + ""));
        countList.add(new CountDto(quantizedDataTitle, "新签会员数", newMemberCount + ""));
        countList.add(new CountDto(quantizedDataTitle, "未结课会员数（含新签&续费）", noEndingCount + ""));
        countList.add(new CountDto(quantizedDataTitle, "净会员增长", newGrowthCount + ""));
        countList.add(new CountDto(quantizedDataTitle, "现金流（新签+续费金额）", cashFlowAmount + ""));

        return countList;
    }


    /**
     * 判断开始日期和结束日期
     */
    private R<Object> judgeDate(String beginDate, String endDate) throws Exception {
        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate)) {
            return R.fail("请选择开始和结束日期");
        }
        Date bDate = DateUtil.parseDate(beginDate);
        Date eDate = DateUtil.parseDate(endDate);
        if (eDate.getTime() < bDate.getTime()) {
            return R.fail("结束日期必须大于开始日期");
        }
        if (DateUtil.differentDays(bDate, eDate) > 366) {
            return R.fail("查询的天数不能超过366天");
        }
        return R.ok();
    }


    /**
     * 按客户来源分类
     */
    private String getCustomSource(String customSource) {
        if (StringUtils.isBlank(customSource) || customSource.equals(EnumCustomSource.QT.getUid())) {
            return "其他";
        } else if (customSource.equals(EnumCustomSource.ZR.getUid())) {
            return "自然到访";
        } else if (customSource.equals(EnumCustomSource.ZJ.getUid())) {
            return "转介绍";
        } else if (customSource.equals(EnumCustomSource.DT.getUid()) || customSource.equals(EnumCustomSource.SQ.getUid())
                || customSource.equals(EnumCustomSource.HW.getUid()) || customSource.equals(EnumCustomSource.XQ.getUid())
                || customSource.equals(EnumCustomSource.SC.getUid())
        ) {
            return "地推";
        } else if (customSource.equals(EnumCustomSource.DY.getUid()) || customSource.equals(EnumCustomSource.SPH.getUid())
                || customSource.equals(EnumCustomSource.DP.getUid()) || customSource.equals(EnumCustomSource.MT.getUid())
                || customSource.equals(EnumCustomSource.XHX.getUid())
        ) {
            return "线上";
        } else {
            return "其他";
        }
    }

    /**
     * 区分中、英文科目
     */
    private String getSubjectType(String projectName) {
        if (projectName.contains("WT") || projectName.contains("JT")
                || projectName.contains("wt") || projectName.contains("jt")) {
            return "英文";
        } else {
            return "中文";
        }
    }

}
